package net.cassite.pure.ioc.handlers.param;

import java.lang.annotation.Annotation;

import net.cassite.pure.ioc.AnnotationHandlingException;
import net.cassite.pure.ioc.IOCController;
import net.cassite.pure.ioc.Scope;
import net.cassite.pure.ioc.annotations.Use;
import net.cassite.pure.ioc.handlers.IrrelevantAnnotationHandlingException;
import net.cassite.pure.ioc.handlers.ParamAnnotationHandler;
import net.cassite.pure.ioc.handlers.ParamHandlerChain;
import net.cassite.style.reflect.MemberSup;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static net.cassite.style.Style.*;
import static net.cassite.style.aggregation.Aggregation.*;

/**
 * Handler for Use annotation. <br>
 * returns the instance of the class "use" annotation represents.
 *
 * @author wkgcass
 * @see Use
 */
public class ParamUseHandler extends IOCController implements ParamAnnotationHandler {

        private static final Logger LOGGER = LoggerFactory.getLogger(ParamUseHandler.class);

        @Override
        public boolean canHandle(Annotation[] annotations) {
                for (Annotation ann : annotations) {
                        if (ann.annotationType() == Use.class) {
                                return true;
                        }
                }
                return false;
        }

        @Override
        public Object handle(Scope scope, MemberSup<?> caller, Class<?> cls, Class<?> expectedClass, Annotation[] toHandle, ParamHandlerChain chain) throws AnnotationHandlingException {
                LOGGER.debug("Entered ParamUseHandler with args:\n\tcaller:\t{}\n\tcls:\t{}\n\ttoHandle:\t{}\n\tchain:\t{}",
                        caller, cls, toHandle, chain);

                try {
                        return chain.next().handle(scope, caller, cls, expectedClass, toHandle, chain);
                } catch (IrrelevantAnnotationHandlingException e) {
                        LOGGER.debug("Start handling with ParamUseHandler");

                        return If((Use) $(toHandle).findOne(a -> a.annotationType() == Use.class), use -> {
                                Class<?> clazz = use.cls();
                                if (clazz != Use.class) {
                                        return get(scope, clazz, expectedClass);
                                }
                                String value = use.value();
                                if (!"".equals(value)) {
                                        return scope.get(value);
                                }
                                throw new AnnotationHandlingException("empty Use annotation");
                        }).Else(() -> {
                                throw new IrrelevantAnnotationHandlingException();
                        });
                }
        }

}
